Skip to content

feat(review-fix-loop): deliver and evaluate standalone local_commit workflow - #111

Merged
shaug merged 2 commits into
mainfrom
claude/99-review-fix-loop-local-commit
Jul 31, 2026
Merged

feat(review-fix-loop): deliver and evaluate standalone local_commit workflow#111
shaug merged 2 commits into
mainfrom
claude/99-review-fix-loop-local-commit

Conversation

@shaug

@shaug shaug commented Jul 31, 2026

Copy link
Copy Markdown
Owner

Summary

Delivers and evaluates the standalone review-fix-loop local_commit workflow: the actual end-to-end loop design/review-fix-loop.md's "Workflow" section describes (steps 1 "Resolve" through 9 "Return"), composing the three already-merged children of epic #95 without reimplementing any of their internals.

  • skills/review-fix-loop/scripts/local_commit.pyrun_local_commit(...) composes:
  • Enforces the invocation fix-cycle budget (a cycle is reserved and consumed the moment an attempt starts, regardless of outcome).
  • Commits selected fixes in an isolated attempt and promotes only a converged candidate; never performs a remote write under local_commit.
  • Detects the candidate-visible non-convergence stops the design names (expanding_findings, oscillation, repeated_failed_attempt, cycle_budget_exhausted) without second-guessing a finding that simply survives one fix within budget (see references/local-commit.md for why that specific case is deliberately not an automatic early stop).
  • Reports declined findings and their rationale, explicit retained-commit (unpushed_commits) and operator_action evidence for every non-converged stop.
  • skills/review-fix-loop/references/local-commit.md documents the composition, the three host-boundary ports (reviewer, decide, apply_fix), and every terminal state this module returns.
  • skills/review-fix-loop/scripts/tests/test_local_commit.py — 21 end-to-end tests against real temporary Git repositories (no mocked Git state): immediate convergence, one and multiple fix cycles, budget exhaustion, a validation failure that is unavailable/untractable/tractable, a declined finding and a scope-expanding fix (operator input), expanding and oscillating finding sets, repeated failed attempts, interrupted-attempt recovery, an already-held candidate lock, an attempted reviewer mutation, a host without fresh-subagent support, a bound source-binding's ahead/behind reporting, and a regression test reproducing (and proving fixed) a stale-disposition defect a first review pass found.
  • Updates SKILL.md to document the new entry point and records today's changelog entry.

Review history

Two full fresh-subagent review-code-change passes:

  1. Initial pass (head 498983d): changes_required — one blocking correctness finding (a resumed invocation could leave a converged result carrying both a stale declined disposition and the real selected/fixed one for the same finding_id, reachable through this module's own public resume_checkpoint parameter) and one strong_recommendation finding (a local_commit invocation carrying a schema-legal source_binding still reported source: unavailable instead of the terminal-result contract's own named "local ahead/behind state ... when a source is bound").
  2. Fix cycle (head cc9d86a): both findings fixed — _State.record_finding_disposition now always replaces any prior entry for a finding_id before appending a new one; _checkpoint_source_status/_terminal_source_status now compute real ahead/behind counts via git rev-list --count whenever a source binding is present. Two regression tests added reproducing each defect directly.
  3. Re-review (head cc9d86a): clean. Both fixes independently verified; solution-simplicity and code-simplicity also run fresh. One non-gating defer finding remains (the two source-status builders share near-duplicate ahead/behind computation) — preserved per the review-and-merge-gates instruction to keep deferred findings without expanding the PR; noted for a future pass.

Acceptance ledger (ticket #99)

Criterion Evidence Status
A fixable candidate reaches converged only after a complete clean re-review and required validation FixCycleTests, _check_converged_requires_clean_evidence in validate.py enforced on every returned document pass
Declined findings and their rationale remain visible in the terminal result OperatorInputTests.test_declined_finding_blocks_on_operator_input_and_stays_visible, RegressionTests pass
Budget exhaustion, validation failure, interruption, and approval/input requirements map to the specified terminal states BudgetExhaustionTests, ValidationFailureTests, RecoveryTests, OperatorInputTests, StopConditionTests pass
No remote write occurs in any local_commit path run_local_commit never calls git push/any remote-mutating command; publication.status is always not_applicable pass
Failed or non-converged runs preserve and report recoverable commits BudgetExhaustionTests, StopConditionTests (unpushed_commits always populated) pass
End-to-end evaluation demonstrates the result is usable without caller-specific knowledge 21 end-to-end fixtures drive the public run_local_commit API with only the three documented host-boundary ports, no caller-specific state pass

Validation

  • python3 -m unittest discover -s skills/review-fix-loop/scripts/tests -p 'test_*.py' — 253 tests, OK
  • just format — no changes needed
  • just lint — All checks passed (ruff, mdformat, skills-ref validate, plugin packaging)
  • just test — full repository gate, OK (implement-epic 17, implement-ticket 88, review-code-change 9, review-code-simplicity 3, review-correctness 8, review-fix-loop 253, review-solution-simplicity 5, review-suite 318)

Fixes #99

Co-Authored-By: Claude Sonnet 5 noreply@anthropic.com

shaug and others added 2 commits July 30, 2026 22:17
…orkflow

## Summary
- Add `scripts/local_commit.py`'s `run_local_commit(...)`, composing the
  merged contract (#96), local-execution (#97), and reviewer-orchestration
  (#98) leaves into the actual end-to-end `local_commit` loop design's
  "Workflow" section describes: resolve, establish evidence, review, decide,
  fix, validate and commit, invalidate and repeat, publish (never, under
  `local_commit`), and return one schema-valid terminal result.
- Enforce the invocation fix-cycle budget, commit selected fixes in isolated
  attempts, promote only a converged candidate, and detect the
  candidate-visible non-convergence stops (`expanding_findings`,
  `oscillation`, `repeated_failed_attempt`, `cycle_budget_exhausted`) without
  second-guessing a finding that simply survives one fix within budget.
- Add `references/local-commit.md` documenting the composition, the three
  host-boundary ports (`reviewer`, `decide`, `apply_fix`), and every terminal
  state this module returns.
- Add `scripts/tests/test_local_commit.py`: 18 end-to-end tests against real
  temporary Git repositories (no mocked Git state) covering immediate
  convergence, one and multiple fix cycles, budget exhaustion, a validation
  failure that is unavailable/untractable/tractable, a declined finding and a
  scope-expanding fix (both surfaced as operator input), expanding and
  oscillating finding sets, repeated failed attempts, interrupted-attempt
  recovery, an already-held candidate lock, an attempted reviewer mutation,
  and a host without fresh-subagent support.
- Update `SKILL.md` to document the new entry point and record the changelog
  entry for today, backfilling the prior day's topmost entry's SHA.

## Why
- Closes #99, the only unblocked child of epic #95: a
  standalone, evaluated `local_commit` workflow that reviews, fixes,
  validates, re-reviews, and converges without remote publication, usable by
  a future caller without caller-specific knowledge.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…und source ahead/behind

## Summary
- `_State.record_finding_disposition` replaces any existing top-level entry
  for a finding_id before appending a new one, in both `finding_dispositions`
  and `unresolved_or_deferred_findings`, instead of letting a declined
  disposition from one pass (or a resumed checkpoint) coexist with a later
  `selected` entry for the same finding once it is actually fixed. Wired into
  every disposition call site (resume reconstruction, the live decline path,
  and the live commit-success path).
- `_checkpoint_source_status`/`_terminal_source_status` report `source:
  {status: "bound", ...}` with real ahead/behind counts (via `git rev-list
  --count`) whenever `candidate.source_binding` is present, instead of
  unconditionally reporting `unavailable` even when a read-only source
  binding exists; `_minimal_blocked_result` (the pre-lock `candidate_busy`
  path) now takes `repo` so it can report the same thing.
- Add regression tests reproducing both defects directly (a finding declined
  then resumed-and-fixed ends up with exactly one, current disposition and
  is no longer reported as unresolved; a `local_commit` invocation carrying
  a `source_binding` reports `bound` with correct ahead/behind counts) plus
  a control test confirming the no-binding path is unaffected.

## Why
- Closes the first review-code-change pass on #99: a `blocking` correctness
  finding (self-contradictory disposition data reachable through this
  module's own public `resume_checkpoint` parameter) and a
  `strong_recommendation` finding (the terminal-result contract's own named
  "local ahead/behind state ... when a source is bound" requirement was
  silently unimplemented).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@shaug
shaug merged commit eaa1ded into main Jul 31, 2026
1 check passed
@shaug
shaug deleted the claude/99-review-fix-loop-local-commit branch July 31, 2026 06:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Deliver and evaluate standalone review-fix-loop local_commit

1 participant